﻿using System;
using System.Diagnostics;
using System.Threading;
using AzureStorageMapper.Criterias.TableStorage;
using AzureStorageMapper.TableStorage;
using AzureStorageMapper.TableStorage.Attributes;
using AzureStorageMapper.TableStorage.RESTCommunicate;
using NUnit.Framework;

namespace AzureStorageMapper.Tests.TableStorage.TableEntityTests
{
    [TestFixture]
    public class FilterTests
    {
        TableContext<SampleTableModel> tc = new TableContext<SampleTableModel>();

        [SetUp]
        public void TestSetUp()
        {
            Trace.TraceInformation("Creating table");
            tc.CreateTable();

            Trace.TraceInformation("Sleep for 5 seconds");
            Thread.Sleep(TimeSpan.FromSeconds(5));

            Trace.TraceInformation("Preparing data");
            for (int i = 1; i < 7; i++)
            {
                SampleTableModel model = new SampleTableModel("default", Guid.NewGuid().ToString());
                model.ColumnOne = "col " + i;
                model.ColumnTwo = i;
                model.ColumnThree = int.MaxValue + i;

                tc.Save(model);
            }
        }

        [TearDown]
        public void TestTearDown()
        {
            Trace.TraceInformation("Sleep for 5 seconds, prepare to tear down data");
            Thread.Sleep(TimeSpan.FromSeconds(5));

            Trace.TraceInformation("deleting table");
            tc.DeleteTable();
        }

        [Test]
        public void ColumnFilterTest()
        {
            Criteria c1 = new Criteria();
            c1.QueryColumn("Column2").QueryOperation(CriteriaOperator.GreaterThanOrEqual).QueryValue(2);

            Criteria c2 = new Criteria();
            c2.QueryColumn("Column2").QueryOperation(CriteriaOperator.LessThan).QueryValue(6);

            Restrietion r = new Restrietion();
            r.And(c1, c2);

            QueryEntitiesResult<SampleTableModel> li = tc.FindEntities(r);

            Assert.AreEqual(4, li.Result.Count);
            foreach (var item in li.Result)
            {
                Trace.TraceInformation("{0} -- {1}  -- {2}", item.ColumnOne, item.ColumnTwo, item.ColumnThree);
            }
            foreach (var item in li.Result)
            {
                Assert.IsTrue(item.ColumnTwo >= 2 && item.ColumnTwo < 6);
            }
        }

        [Test]
        public void TopFilterTest()
        {
            Criteria c1 = new Criteria();
            c1.QueryColumn("Column2").QueryOperation(CriteriaOperator.GreaterThanOrEqual).QueryValue(1);

            Criteria c2 = new Criteria();
            c2.QueryColumn("Column2").QueryOperation(CriteriaOperator.LessThan).QueryValue(4);

            Restrietion r = new Restrietion();
            r.And(c1, c2);

            QueryEntitiesResult<SampleTableModel> li = tc.FindEntities(r, topCount: 4);
            Assert.AreEqual(3, li.Result.Count);

            li = tc.FindEntities(r, topCount: 2);
            Assert.AreEqual(2, li.Result.Count);

            foreach (var item in li.Result)
            {
                Trace.TraceInformation("==> {0} -- {1}  -- {2}", item.ColumnOne, item.ColumnTwo, item.ColumnThree);
            }


            Assert.IsNotNull(li.Continuation);
            Trace.TraceInformation("NextTable: '{0}', NextPartition:'{1}', NextRow: '{2}'",
                                   li.Continuation.NextTableName,
                                   li.Continuation.NextPartitionKey,
                                   li.Continuation.NextRowKey);

            li = tc.FindEntities(r, topCount: 2, continuation: li.Continuation);
            Assert.AreEqual(1, li.Result.Count);
            foreach (var item in li.Result)
            {
                Trace.TraceInformation("--> {0} -- {1}  -- {2}", item.ColumnOne, item.ColumnTwo, item.ColumnThree);
            }

            Assert.IsNull(li.Continuation);
        }

        [TableModel(Name = "SampleQueryTests")]
        internal class SampleTableModel : TableEntity
        {
            [TableColumn]
            public string ColumnOne { get; set; }

            [TableColumn(Name = "Column2")]
            public int ColumnTwo { get; set; }

            [TableColumn]
            public long ColumnThree { get; set; }

            public SampleTableModel(string partitionKey, string rowKey)
                : base(partitionKey, rowKey)
            {
            }
        }
    }
}
